﻿using BCC.Common.Common;
using BCC.Model.Enumeration;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace BCC.Communication.SocketClient
{
    public class client
    {
        Socket clientsocket;

        public client()
        {
            clientsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//初始化服务器
        }
        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public void connected(string ip, int port)
        {
            clientsocket.Connect(ip, port);
            Console.WriteLine("连接成功");
            // clientsocket.bind(new ipendpoint());

            Thread recvthread = new Thread(recvmessage);
            recvthread.IsBackground = true;
            recvthread.Start();
        }

        #region 发送消息
        /// <summary>
        /// 发送聊天消息
        /// </summary>
        /// <param name="mes"></param>
        /// <param name="account"></param>
        public void sendMes(byte[] bytes)
        {
            clientsocket.Send(new MessageProtocol(1, 0, bytes).GetBytes());
        }
        /// <summary>
        /// 发图片
        /// </summary>
        /// <param name="bytes"></param>
        public void sendPicMes(byte[] bytes)
        {
            clientsocket.Send(new MessageProtocol(1, 1, bytes).GetBytes());
        }

        /// <summary>
        /// 发图片和聊天消息
        /// </summary>
        /// <param name="bytes"></param>
        public void sendPicAndStringMes(byte[] bytes)
        {
            clientsocket.Send(new MessageProtocol(1, 2, bytes).GetBytes());
        }

        /// <summary>
        /// 发送聊天消息
        /// </summary>
        /// <param name="mes"></param>
        /// <param name="account"></param>
        public void sendStrMes(string mes,string account)
        {
            string str = account + ";" + mes;
            //clientsocket.Send(new MessageProtocol(1, 0, Encoding.UTF8.GetBytes(str)).GetBytes());
            sendMes(Encoding.UTF8.GetBytes(str));
        }

        /// <summary>
        /// 发送图片
        /// </summary>
        /// <param name="image"></param>
        /// <param name="account"></param>
        public void SendImageMes(Image image, string account)
        {
            byte[] numberBytes = BitConverter.GetBytes(int.Parse(account));

            // 将Image对象转换为字节数组
            byte[] imageBytes = ImageToByteArray(image);

            byte[] dataBytes = new byte[sizeof(int) + imageBytes.Length];
            Buffer.BlockCopy(numberBytes, 0, dataBytes, 0, sizeof(int));
            Buffer.BlockCopy(imageBytes, 0, dataBytes, sizeof(int), imageBytes.Length);

            sendPicMes(imageBytes);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="image"></param>
        /// <param name="account"></param>
        public void SendPicAndStringMes(byte[] PicAndStringBytes, string account)
        {
            byte[] numberBytes = BitConverter.GetBytes(int.Parse(account));

            // 将Image对象转换为字节数组
            //byte[] PicAndStringBytes = ImageToByteArray(image);

            byte[] dataBytes = new byte[sizeof(int) + PicAndStringBytes.Length];
            Buffer.BlockCopy(numberBytes, 0, dataBytes, 0, sizeof(int));
            Buffer.BlockCopy(PicAndStringBytes, 0, dataBytes, sizeof(int), PicAndStringBytes.Length);

            sendPicAndStringMes(PicAndStringBytes);
        }

        //public static byte[] ConvertDataToBytes(int number, Image image)
        //{
        //    byte[] numberBytes = BitConverter.GetBytes(number);
        //    byte[] imageBytes = ImageToByteArray(image);

        //    byte[] dataBytes = new byte[sizeof(int) + imageBytes.Length];
        //    Buffer.BlockCopy(numberBytes, 0, dataBytes, 0, sizeof(int));
        //    Buffer.BlockCopy(imageBytes, 0, dataBytes, sizeof(int), imageBytes.Length);

        //    return dataBytes;
        //}

        private static byte[] ImageToByteArray(Image image)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                image.Save(ms, image.RawFormat);
                return ms.ToArray();
            }
        }

        /// <summary>
        /// 发送登录信息
        /// </summary>
        /// <param name="account"></param>
        public void sendLoginMes(string account)
        {
            clientsocket.Send(new MessageProtocol(0, 0, Encoding.UTF8.GetBytes(account)).GetBytes());
        }

        #endregion
        /// <summary>
        /// 接受信息
        /// </summary>
        private void recvmessage()
        {
            try
            {
                //byte[] strbyte = new byte[500 * 1024];
                //int len = clientsocket.Receive(strbyte);
                ReceiveData(clientsocket);
                //BCC.MainWindow.AddReceivedUserControl(UserControlMessageReceived received,  text,  time);

                //Console.WriteLine(Encoding.Default.GetString(strbyte, 0, len));
            }
            catch (Exception e) //服务器关闭
            {
                Console.WriteLine("服务器关闭");
                Thread.CurrentThread.Abort();//关闭时切断进程
            }
            recvmessage();
        }


        public static void ReceiveData(Socket socket)  // 接收消息函数(传入一个socket对象)
        {
            try
            {
                MessageProtocol mp = null;
                int ReceiveLength = 0;
                byte[] staticReceiveBuffer = new byte[65536];  // 接收缓冲区(固定长度)
                byte[] dynamicReceiveBuffer = new byte[] { };  // 累加数据缓存(不定长)
                do
                {
                    ReceiveLength = socket.Receive(staticReceiveBuffer);  // 同步接收数据
                    dynamicReceiveBuffer = CombineBytes(dynamicReceiveBuffer, 0, dynamicReceiveBuffer.Length, staticReceiveBuffer, 0, ReceiveLength);  // 将之前多余的数据与接收的数据合并,形成一个完整的数据包
                    if (ReceiveLength <= 0)  // 如果接收到的数据长度小于0(通常表示socket已断开,但也不一定,需要进一步判断,此处可以忽略)
                    {
                        break;  // 终止接收循环
                    }
                    else if (dynamicReceiveBuffer.Length < MessageProtocol.HEADLENGTH)  // 如果缓存中的数据长度小于协议头长度,则继续接收
                    {
                        continue;  // 跳过本次循环继续接收数据
                    }
                    else  // 缓存中的数据大于等于协议头的长度(dynamicReadBuffer.Length >= 6)
                    {
                        var headInfo = MessageProtocol.GetHeadInfo(dynamicReceiveBuffer);  // 解读协议头的信息
                        while (dynamicReceiveBuffer.Length - MessageProtocol.HEADLENGTH >= headInfo.DataLength)  // 当缓存数据长度减去协议头长度大于等于实际数据的长度则进入循环进行拆包处理
                        {
                            mp = new MessageProtocol(dynamicReceiveBuffer);  // 拆包
                            dynamicReceiveBuffer = mp.MoreData;  // 将拆包后得出多余的字节付给缓存变量,以待下一次循环处理数据时使用,若下一次循环缓存数据长度不能构成一个完整的数据包则不进入循环跳到外层循环继续接收数据并将本次得出的多余数据与之合并重新拆包,依次循环。
                            headInfo = MessageProtocol.GetHeadInfo(dynamicReceiveBuffer);  // 从缓存中解读出下一次数据所需要的协议头信息,已准备下一次拆包循环,如果数据长度不能构成协议头所需的长度,拆包结果为0,下一次循环则不能成功进入,跳到外层循环继续接收数据合并缓存形成一个完整的数据包
                                                                                           //if (mp.Command == 0 && mp.Param == 1)
                                                                                           //{
                                                                                           //    socket.Send(new MessageProtocol(0, 0, Encoding.UTF8.GetBytes("Goodbye\r\n再见!")).GetBytes());
                                                                                           //    return;
                                                                                           //}

                            ResponseRequest(socket, mp.GetMessage());
                        } // 拆包循环结束
                    }
                } while (ReceiveLength > 0);
            }
            finally
            {
                Console.WriteLine("客户 \'{0}\' 已离开", socket.RemoteEndPoint.ToString());
                socket.Close();
            }
        }

        private static void ResponseRequest(Socket socket, (byte Command, byte Param, int DataLength, byte[] MessageData) message)
        {
            var buffer = message.MessageData;
            var len = message.DataLength;
            if (len > 0)
            {
                //判断是否是png文件
                if (len >= 8 && buffer[0] == 0x89 && buffer[1] == 0x50 && buffer[2] == 0x4E
                    && buffer[3] == 0x47 && buffer[4] == 0x0D && buffer[5] == 0x0A
                    && buffer[6] == 0x1A && buffer[7] == 0x0A && len == 8)
                {
                    Console.WriteLine("这是 png 格式的文件");
                    BCC.VB.ViewCommunication.Monitor.MonitorPicCenter(message.MessageData, TimeHelper.getTimeHHmmss(), ImageType.Png);
                }
                //判断是否是jpg文件
                else if (len >= 12 && buffer[0] == 0xFF && buffer[1] == 0xD8 && buffer[2] == 0xFF
                    && buffer[3] == 0xE0 && buffer[6] == 0x4A && buffer[7] == 0x46
                    && buffer[8] == 0x49 && buffer[9] == 0x46 && buffer[10] == 0x00
                    && buffer[11] == 0x01 && len == 12)
                {
                    Console.WriteLine("这是 jpg 格式的文件");
                    //string text = Encoding.UTF8.GetString(message.MessageData);
                    BCC.VB.ViewCommunication.Monitor.MonitorPicCenter(message.MessageData, TimeHelper.getTimeHHmmss(), ImageType.Jpg);
                }
                //如果都不是，则说明接收到的是字符串
                else
                {
                    Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, len));
                    string text = Encoding.UTF8.GetString(message.MessageData);
                    BCC.VB.ViewCommunication.Monitor.MonitorCenter(text, TimeHelper.getTimeHHmmss());
                }
            }

        }

        public static byte[] CombineBytes(byte[] firstBytes, int firstIndex, int firstLength, byte[] secondBytes, int secondIndex, int secondLength)
        {
            byte[] bytes = null;
            MemoryStream ms = new MemoryStream();
            ms.Write(firstBytes, firstIndex, firstLength);
            ms.Write(secondBytes, secondIndex, secondLength);
            bytes = ms.ToArray();
            ms.Close();
            return (bytes);
        }
    }
}
